using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace OverSizeImage
{
    

    /// <summary>
    /// ElementControl.xaml 的交互逻辑
    /// </summary>
    public partial class ElementControl : UserControl
    {
        public ElementBaseModel Info
        {
            get { return (ElementBaseModel)GetValue(InfoProperty); }
            set { SetValue(InfoProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Info.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InfoProperty =
            DependencyProperty.Register("Info", typeof(ElementBaseModel), typeof(ElementControl), new PropertyMetadata(null, (sender, e) =>
            {
                var dp = sender as ElementControl;
                if (dp == null) return;
                dp.GetInfo();
            }));



        public Visibility NameVisit
        {
            get { return (Visibility)GetValue(NameVisitProperty); }
            set { SetValue(NameVisitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NameVisit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NameVisitProperty =
            DependencyProperty.Register("NameVisit", typeof(Visibility), typeof(ElementControl), new PropertyMetadata(Visibility.Collapsed));



        public ObservableCollection<Path> PathList
        {
            get { return (ObservableCollection<Path>)GetValue(PathListProperty); }
            set { SetValue(PathListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PathList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PathListProperty =
            DependencyProperty.Register("PathList", typeof(ObservableCollection<Path>), typeof(ElementControl), new PropertyMetadata(null));


        public double ScaleValue
        {
            get { return (double)GetValue(ScaleValueProperty); }
            set { SetValue(ScaleValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScaleValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScaleValueProperty =
            DependencyProperty.Register("ScaleValue", typeof(double), typeof(ElementControl), new PropertyMetadata(1.0));


        public Visibility ShowLabel
        {
            get { return (Visibility)GetValue(ShowLabelProperty); }
            set { SetValue(ShowLabelProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowLabel.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowLabelProperty =
            DependencyProperty.Register("ShowLabel", typeof(Visibility), typeof(ElementControl), new PropertyMetadata(Visibility.Visible));



        public double ElementWidth
        {
            get { return (double)GetValue(ElementWidthProperty); }
            set { SetValue(ElementWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementWidthProperty =
            DependencyProperty.Register("ElementWidth", typeof(double), typeof(ElementControl), new PropertyMetadata(10.0));



        public double ElementHeight
        {
            get { return (double)GetValue(ElementHeightProperty); }
            set { SetValue(ElementHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementHeightProperty =
            DependencyProperty.Register("ElementHeight", typeof(double), typeof(ElementControl), new PropertyMetadata(10.0));

        public PointCollection PolyPoints
        {
            get { return (PointCollection)GetValue(PolyPointsProperty); }
            set { SetValue(PolyPointsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PolyPoints.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PolyPointsProperty =
            DependencyProperty.Register("PolyPoints", typeof(PointCollection), typeof(ElementControl), new PropertyMetadata(null));





        public ObservableCollection<Thumb> PolyAdornerList
        {
            get { return (ObservableCollection<Thumb>)GetValue(PolyAdornerListProperty); }
            set { SetValue(PolyAdornerListProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PolyAdornerList.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PolyAdornerListProperty =
            DependencyProperty.Register("PolyAdornerList", typeof(ObservableCollection<Thumb>), typeof(ElementControl), new PropertyMetadata(null));

        public Brush ThumbBrush
        {
            get { return (Brush)GetValue(ThumbBrushProperty); }
            set { SetValue(ThumbBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ThumbBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ThumbBrushProperty =
            DependencyProperty.Register("ThumbBrush", typeof(Brush), typeof(ElementControl), new PropertyMetadata(Brushes.White));

        public bool HitEnabled
        {
            get { return (bool)GetValue(HitEnabledProperty); }
            set { SetValue(HitEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HitEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HitEnabledProperty =
            DependencyProperty.Register("HitEnabled", typeof(bool), typeof(ElementControl), new PropertyMetadata(false));


        private void GetInfo()
        {
            if (Info == null) return;
            Info.PropertyChanged += Info_PropertyChanged;

            switch (Info.Shape)
            {
                case ShapeEnum.矩形:
                case ShapeEnum.圆形:
                    Canvas.SetLeft(this, Info.X);
                    Canvas.SetTop(this, Info.Y);
                    this.ElementWidth = Info.Width;
                    this.ElementHeight = Info.Height;
                    break;
                case ShapeEnum.多边形:
                    if (Info.Points != null)
                    {
                        RefushPolygon();
                        Info.Points.CollectionChanged += Points_CollectionChanged;
                    }
                    break;
                case ShapeEnum.线段:
                    if (Info.PathList != null)
                    {
                        PathList = new ObservableCollection<Path>();
                        foreach (var item in Info.PathList.OrderByDescending(x => x.Result))
                        {
                            Path path = new Path() { Stroke = item.Result == 1 ? Brushes.Green : Brushes.Red };
                            List<LineSegment> segmens = new List<LineSegment>();
                            if (item.Points == null || item.Points.Count() == 0)
                                continue;
                            foreach (var point in item.Points)
                            {
                                segmens.Add(new LineSegment(new Point(point.X - Info.X, point.Y - Info.Y), true));
                            }
                            PathFigure figure = new PathFigure(new Point(item.Points.First().X - Info.X, item.Points.First().Y - Info.Y) , segmens, false);
                            PathGeometry geometry = new PathGeometry();
                            geometry.Figures.Add(figure);
                            path.Data = geometry;

                            Binding thincessBind = new Binding();
                            thincessBind.Source = this;
                            thincessBind.Path = new PropertyPath("ScaleValue");
                            thincessBind.Mode = BindingMode.TwoWay;
                            thincessBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                            thincessBind.Converter = this.FindResource("NumDivideConvert") as IValueConverter;
                            thincessBind.ConverterParameter = "2";
                            path.SetBinding(Path.StrokeThicknessProperty, thincessBind);
                            PathList.Add(path);
                        }
                    }
                    Canvas.SetLeft(this, Info.X);
                    Canvas.SetTop(this, Info.Y);
                    this.ElementWidth = Info.Width;
                    this.ElementHeight = Info.Height;
                    break;
            }
        }

        private void RefushPolygon()
        {
            PolyAdornerList = new ObservableCollection<Thumb>();
            foreach (var item in Info.Points)
            {
                Thumb thumb = new Thumb() { Tag = Info.Points.IndexOf(item) };
                thumb.HorizontalAlignment = HorizontalAlignment.Stretch;
                thumb.VerticalAlignment = VerticalAlignment.Stretch;
                thumb.Cursor = Cursors.Cross;
                thumb.DragDelta += Thumb_DragDelta;
                thumb.Background = Brushes.Green;
                thumb.Opacity = 1;
                thumb.Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(ThumbBrush)
                };
                Binding widthBind = new Binding();
                widthBind.Source = this;
                widthBind.Path = new PropertyPath("ScaleValue");
                widthBind.Mode = BindingMode.TwoWay;
                widthBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                widthBind.Converter = new NumDivideConvert();
                widthBind.ConverterParameter = 10;
                thumb.SetBinding(Thumb.WidthProperty, widthBind);
                Binding heightBind = new Binding();
                heightBind.Source = this;
                heightBind.Path = new PropertyPath("ScaleValue");
                heightBind.Mode = BindingMode.TwoWay;
                heightBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                heightBind.Converter = new NumDivideConvert();
                heightBind.ConverterParameter = 10;
                thumb.SetBinding(Thumb.HeightProperty, heightBind);

                PolyAdornerList.Add(thumb);
                Canvas.SetLeft(thumb, item.X - 5 / ScaleValue);
                Canvas.SetTop(thumb, item.Y - 5 / ScaleValue);
            }
        }

        private void Points_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            PolyPoints = new PointCollection(Info.Points);

            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                default:
                    if (PolyAdornerList != null)
                        foreach (var item in PolyAdornerList)
                        {
                            item.DragDelta -= Thumb_DragDelta;
                        }
                    RefushPolygon();
                    break;
            }
            
        }

        private FrameworkElementFactory GetFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Ellipse));
            fef.SetValue(Ellipse.FillProperty, back);
            return fef;
        }

        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var thumb = sender as Thumb;
            if (thumb == null) return;
            if (int.TryParse(thumb.Tag.ToString(), out int index))
            {
                if (index >= Info.Points.Count) return;
                Info.Points[index] = new Point(Info.Points[index].X + e.HorizontalChange, Info.Points[index].Y + e.VerticalChange);
                Canvas.SetLeft(thumb, Info.Points[index].X - 5 / ScaleValue);
                Canvas.SetTop(thumb, Info.Points[index].Y - 5 / ScaleValue);
                PolyPoints = new PointCollection(Info.Points);
            }
        }

        private void Info_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "X":
                    Canvas.SetLeft(this, Info.X);
                    break;
                case "Y":
                    Canvas.SetTop(this, Info.Y);
                    break;
                case "Width":
                    this.ElementWidth = Info.Width;
                    break;
                case "Height":
                    this.ElementHeight = Info.Height;
                    break;
                case "IsSelected":
                    Panel.SetZIndex(this, Info.IsSelected ? 1 : 0);
                    break;
                case "Visit":
                    this.Visibility = Info.Visit;
                    break;
            }
        }

        public ElementControl()
        {
            InitializeComponent();
        }
    }
}
